/*  ------------------------------------------------------------------------
	 NQ Common Services Library
	 
	 Homepage: http://www.awzhome.de/
	 ------------------------------------------------------------------------
	 
	 The contents of this file are subject to the Mozilla Public License
	 Version 1.1 (the "License"); you may not use this file except in
	 compliance with the License. You may obtain a copy of the License at
	 http://www.mozilla.org/MPL/
	 
	 Software distributed under the License is distributed on an "AS IS"
	 basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	 License for the specific language governing rights and limitations
	 under the License.
	
	 The Original Code is code of NQ Common Services Library.

	 The Initial Developer of the Original Code is Andreas Weizel.
	 Portions created by the Initial Developer are
	 Copyright (C) 2006-2012 Andreas Weizel. All Rights Reserved.
	 
	 Contributor(s): (none)
	 
	 Alternatively, the contents of this file may be used under the terms
	 of the GNU General Public License Version 2.0 or later (the "GPL"),
	 or the GNU Lesser General Public License Version 2.1 or later (the
	 "LGPL"), in which case the provisions of the GPL or the LGPL are
	 applicable instead of those above. If you wish to allow use of your
	 version of this file only under the terms of the GPL or the LGPL and
	 not to allow others to use your version of this file under the MPL,
	 indicate your decision by deleting the provisions above and replace
	 them with the notice and other provisions required by the GPL or the
	 LGPL. If you do not delete the provisions above, a recipient may use
	 your version of this file under the terms of any of the MPL, the GPL
	 or the LGPL.
	 ------------------------------------------------------------------------
*/

using System;
using System.Windows.Media;
using AWZhome.NQ.Core;
using AWZhome.NQ.Core.Fluent;

namespace AWZhome.NQ.CommonServices
{
	/// <summary>
	/// Helper class which encapsulates much of the initialization code needed for views.
	/// </summary>
	/// <remarks>
	/// You don't need to use this class to create a view, you may also directly implement
	/// <see cref="AWZhome.NQ.CommonServices.IView">INQViewService</see>
	/// interface instead. But this class could reduce the amount of needed code
	/// for default tasks like storing the view's data.
	/// </remarks>
	public abstract class ViewServiceBase : IView
	{
		private IViewManager _viewManager;
		private ISession _sessionService;

		private bool _initialized = false;
		protected string _name;
		protected string _context;
		private int _position = -1;
		private ViewDisplayMode _displayMode = ViewDisplayMode.InClientArea;
		private string _displayName = null;
		private string _toolTip = null;
		private bool _isChanged = false;
		private bool _isDirty = false;
		private bool _isPersisted = true;
		private bool _canBeClosed = true;
		private ImageSource _icon = null;

		/// <summary>
		/// Constructor of the class, used to initialize the view.
		/// </summary>
		/// <param name="sessionService">Instance of the session the view belongs to.</param>
		/// <remarks>
		/// This constructor MUST be called by derived classes to initialize the view correctly.
		/// </remarks>
		public ViewServiceBase(ISession sessionService)
		{
			_sessionService = sessionService;

			// Check if session is supported
			if (!CheckSessionType(_sessionService))
			{
				throw new InvalidOperationException("Session type is not supported.");
			}
		}

		#region Own Members

		/// <summary>
		/// Tests if the session type is supported by the view.
		/// </summary>
		/// <param name="session">Session object.</param>
		/// <returns><c>True</c>, if session type is supported, <c>false</c> otherwise.</returns>
		protected abstract bool CheckSessionType(ISession session);

		/// <summary>
		/// Called when the view is assigned to or removed from a view manager.
		/// </summary>
		/// <param name="viewManager">View manager or <c>null</c>, if the view has been removed from a view manager.</param>
		protected virtual void OnViewManagerSet(IViewManager viewManager)
		{
		}

		#endregion

		#region IView Members

		/// <summary>
		/// Returns the internal (unique) name of the view.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.Name"/>
		public string Name
		{
			get
			{
				return _name;
			}
		}

		/// <summary>
		/// Returns the view's context (name of open file, open chatroom etc.).
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.Context"/>
		public string Context
		{
			get
			{
				return _context;
			}
		}

		/// <summary>
		/// Returns the display name of the view.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.DisplayName"/>
		public virtual string DisplayName
		{
			get
			{
				return _displayName;
			}
			set
			{
				_displayName = value;
				if (_viewManager != null)
				{
					_viewManager.UpdateView(this, false);
				}
			}
		}

		/// <summary>
		/// Returns the tool tip shown when moving mouse cursor over the view's title or tab.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.ToolTip"/>
		public virtual string ToolTip
		{
			get
			{
				return _toolTip;
			}
			set
			{
				_toolTip = value;
				if (_viewManager != null)
				{
					_viewManager.UpdateView(this, false);
				}
			}
		}

		/// <summary>
		/// Returns whether the view should be highlighted to indicate that something important has happened in the view.
		/// </summary>
		/// <remarks>
		/// This flag will be automatically reset by view manager when the view becomes active.
		/// </remarks>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.IsChanged"/>
		public virtual bool IsChanged
		{
			get
			{
				return _isChanged;
			}
			set
			{
				_isChanged = value;
				if (_viewManager != null)
				{
					_viewManager.UpdateView(this, false);
				}
			}
		}

		/// <summary>
		/// Returns whether the view has the "dirty" flag indicating documents with unsaved changes.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.IsDirty"/>
		public virtual bool IsDirty
		{
			get
			{
				return _isDirty;
			}
			set
			{
				_isDirty = value;
				if (_viewManager != null)
				{
					_viewManager.UpdateView(this, false);
				}
			}
		}

		/// <summary>
		/// Returns whether the view may be closed by user.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.CanBeClosed"/>
		public virtual bool CanBeClosed
		{
			get
			{
				return _canBeClosed;
			}
			set
			{
				_canBeClosed = value;
				if (_viewManager != null)
				{
					_viewManager.UpdateView(this, false);
				}
			}
		}

		/// <summary>
		/// Returns whether the contents of the view should be saved in some sort of history storage (e.g. for chat sessions).
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.IsLoggable"/>
		public virtual bool IsLoggable
		{
			get
			{
				return false;
			}
		}

		/// <summary>
		/// Returns whether view is a document view. Shouldn't be used any more.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.IsDocument"/>
		public virtual bool IsDocument
		{
			get
			{
				return false;
			}
		}

		/// <summary>
		/// Returns whether an open view should be persisted when its container is closed.
		/// It will be restored when container is opened for the next time.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.IsPersisted"/>
		public virtual bool IsPersisted
		{
			get
			{
				return _isPersisted;
			}
			set
			{
				_isPersisted = value;
				if (_viewManager != null)
				{
					_viewManager.UpdateView(this, false);
				}
			}
		}

		/// <summary>
		/// Returns the visual object (i.e. control instance) shown in the view.
		/// </summary>
		/// <remarks>
		/// It depends on implementation of view manager, whether this control should be
		/// WPF, Windows Forms or something else.
		/// </remarks>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.DisplayedObject"/>
		public abstract object DisplayedObject
		{
			get;
		}

		/// <summary>
		/// Returns the view's icon to be shown in UI.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.Icon"/>
		public virtual ImageSource Icon
		{
			get
			{
				return _icon;
			}
			set
			{
				_icon = value;
				if (_viewManager != null)
				{
					_viewManager.UpdateView(this, false);
				}
			}
		}

		/// <summary>
		/// Returns the display modes possible for this view. This determines
		/// where the view is allowed do be docked in container window.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.DockingType"/>
		public abstract ViewDisplayMode DockingType
		{
			get;
		}

		/// <summary>
		/// Sets or retrieves the view's current display mode
		/// (i.e. dock direction in container window).
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.DisplayMode"/>
		public ViewDisplayMode DisplayMode
		{
			get
			{
				return _displayMode;
			}
			set
			{
				_displayMode = value;
				if (_viewManager != null)
				{
					_viewManager.UpdateView(this, false);
				}
			}
		}

		/// <summary>
		/// Sets or retrieves the position index of the view.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.Position"/>
		public int Position
		{
			get
			{
				return _position;
			}
			set
			{
				_position = value;
				if (_viewManager != null)
				{
					_viewManager.UpdateView(this, false);
				}
			}
		}

		/// <summary>
		/// Sets or retrieves the instance of view manager service,
		/// this view is assigned to.
		/// </summary>
		/// <remarks>
		/// This property should not be set directly in code. An
		/// <see cref="System.InvalidOperationException"/> might be thrown
		/// in this case. The property is set by the view manager, when
		/// adding the view to it.
		/// </remarks>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.ViewManager"/>
		/// <seealso cref="AWZhome.NQ.CommonServices.IViewManager"/>
		public IViewManager ViewManager
		{
			get
			{
				return _viewManager;
			}
			set
			{
				// Attempt to avoid manually setting the view manager (the view manager should do this)
				if ((value != null) && (value[_name] == null))
				{
					throw new InvalidOperationException("ViewManager can not be set manually.");
				}
				_viewManager = value;
				this.OnViewManagerSet(value);
			}
		}

		/// <summary>
		/// Returns the session service instance this view belongs to.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.Session"/>
		public ISession Session
		{
			get
			{
				if (_sessionService == null)
				{
					// If no session service is given, use the default session
					ISessionManager sessionManager = ServiceCore
						.Get<Services.ISessionManagerService>()
						.To;
					return sessionManager.DefaultSession;
				}
				else
				{
					return _sessionService;
				}
			}
		}

		/// <summary>
		/// Initializes the view with context data.
		/// </summary>
		/// <param name="context">The context data. The meaning of the data depends on the specific view.</param>
		/// <remarks>
		/// <para>If the method is overridden in a derived class, this parent class' version must be called in it.</para>
		/// <para>This method automatically creates a unique name for the view using
		/// <see cref="AWZhome.NQ.CommonServices.IContainerManager.GenerateViewName"/> method.</para>
		/// </remarks>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.Initialize"/>
		public virtual void Initialize(string context)
		{
			if (!_initialized)
			{
				// Find a unique view name
				IContainerManager containerMan = ServiceCore
					.Get<Services.IContainerManagerService>()
					.To;
				_context = context;
				_name = containerMan.GenerateViewName(this);
				_initialized = true;
			}
			else
			{
				// View is already initialized, so not once again!
				throw new InvalidOperationException("View is already initialized.");
			}
		}

		/// <summary>
		/// Method called by view manager when the view becomes active.
		/// </summary>
		/// <param name="oldView">
		/// Instance of the view being active before,
		/// or <c>null</c>, if no view has been active.
		/// </param>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.Activate"/>
		public virtual void Activate(IView oldView)
		{
			// Doing nothing but preventing sub classes from needing to implement this
		}

		/// <summary>
		/// Method called by view manager when the view becomes inactive.
		/// </summary>
		/// <param name="newView">
		/// Instance of the new view being active now,
		/// or <c>null</c>, if no view became active.
		/// </param>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.Deactivate"/>
		public virtual void Deactivate(IView newView)
		{
			// Doing nothing but preventing sub classes from needing to implement this
		}

		/// <summary>
		/// Requests the view to decide if it can be closed.
		/// </summary>
		/// <returns>
		/// If <c>true</c>, the view will be closed by view manager,
		/// otherwise closing will be ignored.
		/// </returns>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.RequestClosing"/>
		public virtual bool RequestClosing()
		{
			// By default always allow to close the view immidiately
			return true;
		}

		/// <summary>
		/// Requests the view to load its contents and configuration.
		/// </summary>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.LoadContents"/>
		public virtual void LoadContents()
		{
			// Doing nothing but preventing sub classes from needing to implement this
		}

		/// <summary>
		/// Requests the view to save its configuration/state.
		/// </summary>
		/// <param name="saveReason">Specifies the reason for saving request.</param>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.SaveContents"/>
		public virtual void SaveContents(ViewSaveReason saveReason)
		{
			// Doing nothing but preventing sub classes from needing to implement this
		}

		/// <summary>
		/// Called by bar service, when a menu or toolbar item is clicked
		/// while the view is active.
		/// </summary>
		/// <param name="barItem">Instance of clicked menu or toolbar item.</param>
		/// <seealso cref="AWZhome.NQ.CommonServices.IView.BarItemClicked"/>
		public virtual void BarItemClicked(IBarItem barItem)
		{
			// Doing nothing but preventing sub classes from needing to implement this
		}

		#endregion

	}
}
